/*
 * Copyright 2012-2014 glodon paas All right reserved. This software is the
 * confidential and proprietary information of glodon paas ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with glodon paas.
 */
package com.glodon.paas.monitor.web.controller;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.glodon.paas.job.exception.JsonException;
import com.glodon.paas.job.model.TaskStatus;
import com.glodon.paas.job.util.JsonUtil;
import com.glodon.paas.monitor.server.biz.domain.TaskEntity;
import com.glodon.paas.monitor.server.biz.service.TaskService;
import com.glodon.paas.monitor.server.dto.MonitorQueryDTO;
import com.glodon.paas.monitor.server.util.DateFormatUtil;
import com.glodon.paas.monitor.web.bean.Messages;
import com.glodon.paas.monitor.web.bean.ModelStatisticsBean;
import com.glodon.paas.util.DateUtil;

/**
 * @author licx 2013-2-1 下午4:57:42
 */
@Controller
public class JobController extends BaseController {

	private static final Logger								logger		= LoggerFactory.getLogger(JobController.class);

	@Autowired
	private TaskService										taskService;

	private ConcurrentHashMap<String, Map<String, String>>	cacheJobMap	= new ConcurrentHashMap<String, Map<String, String>>();

	@RequestMapping(value = "job", method = RequestMethod.GET)
	public ModelAndView doJobQueryList(@RequestParam(value = "jobId", required = false) String jobId, ModelMap model)
			throws JsonException, UnsupportedEncodingException {
		cacheJobMap.clear();
		String from = DateFormatUtil.getIntervalDate(-30, DateFormatUtil.DAFAULT_DATE_FORMAT);
		Date to = new Date();
		String toDate = DateUtil.formatDate(to, DateUtil.DAFAULT_DATE_FORMAT);
		List<Map<String, String>> jobListMap = processJobStatus(false, null, 0, 10, from, toDate, null);
		if (StringUtils.isNotBlank(jobId)) {
			Map<String, String> jobMap = (Map<String, String>) cacheJobMap.get(jobId);
			jobListMap.clear();
			jobListMap.add(jobMap);
		}
		model.put("jobListMap", jobListMap);
		return new ModelAndView("job");
	}

	@RequestMapping(value = "/monitor/downLoadJob", method = RequestMethod.GET)
	public void downLoadJob(@RequestParam(value = "jobId", required = false) String jobId,
			@RequestParam(value = "fromNum", defaultValue = "0") int fromNum,
			@RequestParam(value = "pageNum", defaultValue = "20") int pageNum,
			@RequestParam(value = "from", required = false) String from,
			@RequestParam(value = "to", required = false) String to,
			@RequestParam(value = "typeChoose", required = false) String typeChoose, HttpServletResponse response)
			throws JsonException, UnsupportedEncodingException {
		List<Map<String, String>> status = processJobStatus(false, jobId, fromNum, pageNum, from, to, typeChoose);
		StringBuffer sb = new StringBuffer();
		String title = null;
		title = Messages.getString("jobTitle");
		sb.append(title).append("\r\n");
		if (status.size() != 0) {
			for (Map<String, String> s : status) {
				sb.append("\t" + s.get("jobId")).append(",").append(s.get("originFilename")).append(",\t")
						.append(s.get("jobType")).append(",\t").append(s.get("jobStatus")).append(",\t")
						.append(s.get("inQuqueTime")).append(",\t").append(s.get("jobServerSumbitTime")).append(",\t")
						.append(s.get("completeTime")).append(",\t")
						.append(s.get("waitDuration") == null ? "" : s.get("waitDuration")).append(",")
						.append(s.get("computeDuration") == null ? "" : s.get("computeDuration")).append("\r\n");
			}
		}
		response.setContentType("application/csv");
		response.setHeader("Content-Disposition", "inline; filename=jobReport.csv");
		PrintWriter out = null;
		try {
			response.setCharacterEncoding("GBK");
			out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), "GBK"));
		} catch (UnsupportedEncodingException e) {
			logger.error("downLoadJob(String, String, HttpServletResponse)", e);
		} catch (IOException e) {
			logger.error("downLoadJob(String, String, HttpServletResponse)", e);
		}
		out.print(sb.toString());
		out.close();
	}

	@RequestMapping(value = "jobstatistics", method = RequestMethod.GET)
	public ModelAndView doJobStatistics(@RequestParam(value = "dateChoose", required = false) String dateChoose,
			ModelMap model) throws Exception {
		cacheJobStatisticsMap.clear();
		String date = null;
		if (StringUtils.isNotEmpty(dateChoose)) {
			if (dateChoose.equals("0")) {
				date = DateUtil.getIntervalHour(-1);
			} else if (dateChoose.equals("1")) {
				date = DateUtil.getIntervalDate(-1);
			} else if (dateChoose.equals("3")) {
				date = DateUtil.getIntervalDate(-3);
			} else if (dateChoose.equals("7")) {
				date = DateUtil.getIntervalDate(-7);
			} else if (dateChoose.equals("30")) {
				date = DateUtil.getIntervalDate(-30);
			}
		}
		List<Map<String, String>> mapList = processJobStatus(false, null, 0, 100, date, null, null);
		NumberFormat nf = NumberFormat.getPercentInstance();
		nf.setMinimumFractionDigits(2);
		Map<String, List<Map<String, String>>> groupByJobTypeMap = buildGroupByTaskTypeMap(mapList);
		List<Map<String, String>> jobStatisticsListMap = new ArrayList<Map<String, String>>(groupByJobTypeMap.size());
		List<ModelStatisticsBean> jobStatisticsList = buildModelStatisticsList(nf, groupByJobTypeMap,
				jobStatisticsListMap);
		ModelStatisticsBean jobStatisticsSumDTO = buildModelStatisticsSum(nf, jobStatisticsList);
		Map sumMap = new HashMap();
		if (null != jobStatisticsSumDTO) {
			sumMap = BeanUtils.describe(jobStatisticsSumDTO);
		}
		model.put("sum", sumMap);
		model.put("jobStatisticsListMap", jobStatisticsListMap);
		if (StringUtils.isBlank(dateChoose)) {
			dateChoose = "3";
		}
		model.put("dateChoose", dateChoose);
		return new ModelAndView("jobstatistics");
	}

	private List<Map<String, String>> processJobStatus(boolean needPage, String jobId, int fromNum, int pageNum,
			String from, String to, String typeChoose) throws JsonException, UnsupportedEncodingException {
		MonitorQueryDTO taskQueryDTO = buildMonitorQueryDTO(needPage, jobId, fromNum, pageNum, null, from, to,
				typeChoose);
		List<TaskEntity> list = taskService.getTaskByMonitorQueryDTO(taskQueryDTO);
		LinkedHashMap<String, Set<Map<String, String>>> jobMap = new LinkedHashMap<String, Set<Map<String, String>>>(
				list.size());
		for (TaskEntity entity : list) {
			Map<String, String> taskMap = new HashMap<String, String>();
			buildTaskMap(entity, taskMap);
			String monitorJobId = (String) taskMap.get("jobId");
			if (jobMap.get(monitorJobId) == null) {
				Set<Map<String, String>> taskSet = new HashSet<Map<String, String>>();
				taskSet.add(taskMap);
				jobMap.put(monitorJobId, taskSet);
			} else {
				Set<Map<String, String>> taskSet = jobMap.get(monitorJobId);
				taskSet.add(taskMap);
				jobMap.remove(monitorJobId);
				jobMap.put(monitorJobId, taskSet);
			}
		}
		List<Map<String, String>> status = new ArrayList<Map<String, String>>();
		buildStatusList(jobMap, status);
		return status;
	}

	private void buildStatusList(LinkedHashMap<String, Set<Map<String, String>>> jobMap,
			List<Map<String, String>> status) {
		if (null != jobMap && !jobMap.isEmpty()) {
			for (Map.Entry<String, Set<Map<String, String>>> entry : jobMap.entrySet()) {
				Map<String, String> statusMap = new HashMap<String, String>();
				String monitorJobId = entry.getKey();
				Set<Map<String, String>> taskSet = entry.getValue();
				int createdSize = 0;
				int runningSize = 0;
				int successSize = 0;
				int failureSize = 0;
				int canceledSize = 0;
				int i = 0;
				long waitDuration = 0l;
				long computeDuration = 0l;
				for (Map<String, String> taskMap : taskSet) {
					i++;
					if (null == statusMap.get("taskType") && null != taskMap.get("taskType")) {
						String taskType = (String) taskMap.get("taskType");
						if (taskType.indexOf("gcl") != -1) {
							taskType = "gcl";
						}
						statusMap.put("taskType", taskType);// 工作类型
					}

					if (null == statusMap.get("originFilename") && null != taskMap.get("originFilename")) {
						String originFilename = (String) taskMap.get("originFilename");
						statusMap.put("originFilename", originFilename);// 文件名称
					}

					if (i == taskSet.size()) {
						if (null != taskMap.get("inQuqueTime")) {
							statusMap.put("inQuqueTime", taskMap.get("inQuqueTime"));// 提交时间
						}
						if (null != taskMap.get("jobServerSumbitTime")) {
							statusMap.put("jobServerSumbitTime", taskMap.get("jobServerSumbitTime"));// 创建时间
						}
						if (null != taskMap.get("computeTime")) {
							statusMap.put("computeTime", taskMap.get("computeTime"));// 该Job的第一个Task的开始处理时间
						}
					}
					if (i == 1 && null != taskMap.get("endTime")) {
						statusMap.put("completeTime", taskMap.get("endTime"));// 该Job的最后一个Task的完成时间
					}
					String taskStatus = taskMap.get("taskStatus");
					if (StringUtils.isNotBlank(taskStatus)) {
						if (taskStatus.equals(TaskStatus.created.toString())) {
							createdSize++;
						} else if (taskStatus.equals(TaskStatus.running.toString())) {
							runningSize++;
						} else if (taskStatus.equals(TaskStatus.success.toString())) {
							successSize++;
						} else if (taskStatus.equals(TaskStatus.failure.toString())) {
							failureSize++;
						} else if (taskStatus.equals(TaskStatus.canceled.toString())) {
							canceledSize++;
						}
					}
					if (null != taskMap.get("waitDuration")) {
						String taskWaitDuration = taskMap.get("waitDuration");
						waitDuration = waitDuration + Long.valueOf(taskWaitDuration).longValue();
					}
					if (null != taskMap.get("computeDuration")) {
						String taskComputeDuration = taskMap.get("computeDuration");
						computeDuration = computeDuration + Long.valueOf(taskComputeDuration).longValue();
					}
				}
				statusMap.put("jobId", monitorJobId);// 工作编号
				statusMap.put("taskSize", String.valueOf(taskSet.size()));// 任务数

				// 工作状态
				if (createdSize == taskSet.size()) {
					statusMap.put("jobStatus", TaskStatus.created.toString());
				} else if (runningSize == taskSet.size()) {
					statusMap.put("jobStatus", TaskStatus.running.toString());
				} else if (successSize == taskSet.size()) {
					statusMap.put("jobStatus", TaskStatus.success.toString());
				} else if (failureSize == taskSet.size()) {
					statusMap.put("jobStatus", TaskStatus.failure.toString());
				} else if (canceledSize == taskSet.size()) {
					statusMap.put("jobStatus", TaskStatus.canceled.toString());
				} else {
					if (runningSize > 0 && runningSize < taskSet.size()) {
						statusMap.put("jobStatus", TaskStatus.running.toString());
					} else if (failureSize > 0 && failureSize < taskSet.size()) {
						statusMap.put("jobStatus", TaskStatus.failure.toString());
					} else if (canceledSize > 0 && canceledSize < taskSet.size()) {
						statusMap.put("jobStatus", TaskStatus.canceled.toString());
					}
				}
				if (null != statusMap.get("jobStatus")) {
					statusMap.put("modelStatus", statusMap.get("jobStatus"));
				}
				statusMap.put("computeDuration", String.valueOf(computeDuration));
				statusMap.put("waitDuration", String.valueOf(waitDuration));

				if (StringUtils.isNotBlank(monitorJobId)) {
					cacheJobMap.put(monitorJobId, statusMap);
				}
				status.add(statusMap);
			}
		}
	}

	@RequestMapping(value = "jobDetail", method = RequestMethod.GET)
	@ResponseBody
	public String getJobDetail(@RequestParam("jobId") String jobId) throws Exception {
		Map<String, String> jobMap = (Map<String, String>) cacheJobMap.get(jobId);
		if (null == jobMap) {
			jobMap = new HashMap<String, String>();
		}
		return JsonUtil.mapToJson(jobMap);
	}

	@RequestMapping(value = "jobStatisticsDetail", method = RequestMethod.GET)
	@ResponseBody
	public String getJobStatisticsDetail(@RequestParam("jobType") String jobType) throws Exception {
		Map<String, String> jobStatisticsMap = (Map<String, String>) cacheJobStatisticsMap.get(jobType);
		if (null == jobStatisticsMap) {
			jobStatisticsMap = new HashMap<String, String>();
		}
		return JsonUtil.mapToJson(jobStatisticsMap);
	}
}
